#include "broker.h"
#include <string>
#include <iostream>

using std::cerr;

//
// InitServerJob methods
//
InitServerJob::InitServerJob(Socket* socket, Context* ctx) {
    this->ctx = ctx;
    this->socket = socket;
}

Job* InitServerJob::execute() {
    //TODO:
    //    1. read client id
    string id = readId(socket);
    cerr << "recieved id: " << id << "\n";
    if (ctx->broker(id)) {
        closeConnectionWithError(socket, ALREADY_CONNECTED_ERR);
    }
    Broker* broker = new Broker(id, socket);
    ctx->put(broker);
    //    2. check if exist such broker
    //    3. authorize
    //    4. create and register broker
    //    5. start PingJob
    return NULL;
}

// 
// Broker methods
//
Broker::Broker(string broker_id, Socket* server_socket) {
    this->broker_id = broker_id;
    this->socket = socket;
}

bool Broker::connect(Socket* socket) {
    cerr << "not implemented\n";
    //this->client_socket_id = client_socket_id;
    return true;
}

void Broker::disconnect() {
    cerr << "not implemented\n";
}

string Broker::id() {
    return broker_id;
}

// 
// Context methods
//
Context::Context(ContextConfig* config) {
    cerr << "conf: " << config->poolSize() << "\n";
    this->config = config;
    this->executor = new Executor(config->poolSize());
}

void Context::enqueue(Job* job) {
    executor->schedule(job);
}

bool Context::put(Broker* broker) {
    brokers[broker->id()] = broker;
    return true;
}

Broker* Context::broker(string client_id) {
    return brokers[client_id];
}

Broker* Context::remove(string client_id) {
    //TODO: remove broker from brokers map
}

// 
// Util fuctions
//
void closeConnectionWithError(Socket* socket, int error) {
    //TODO:
    //    1. send error code
    //send(toBytes(error));
    //    2. close connection
    close(socket->id());
}

string readId(Socket* socket) {
    unsigned char* size_buf = new unsigned char[4];
    int size = recv(socket->id(), (void*) size_buf, 4, 0);
    if (size != 4) {
        cerr << "read id failed\n";
        return NULL;
    }
    
    int id_size = size_buf[0];
    for (int i = 1; i < 4; i++) {
        id_size = (id_size << 8) | size_buf[i];
    }

    cerr << "id size: " << id_size << "\n";

    char* id = new char[id_size + 1];
    if (recv(socket->id(), (void*) id, id_size, 0) != id_size) {
        cerr << "read id fully failed\n";
	return NULL;
    }

    id[id_size] = '\0'; // C style string

    cerr << "id: " << id  << "\n";

    return string(id);
}


//
// Old Broker methods
//
/*
void Broker::run() {
    cerr << "I\'m a new broker " << broker_id << " with pid " << thread_id << "\n";

    char ch;

    size_t buf_size = 1024;
    char* buf = new char[buf_size];
    char size;
    while ((size = recv(host_socket_id, (void *) buf, buf_size, 0)) > 0) {
        for (int i = 0; i < size; i++) {
	    cerr << buf[i];
	}
    }

    cerr << broker_id << " done.\n"; 
}
}*/

